home *** CD-ROM | disk | FTP | other *** search
/ Our Solar System / Our Solar System.iso / shuttle / seesat3 / util.c < prev   
Text File  |  1990-12-24  |  12KB  |  455 lines

  1. /*
  2. UTIL.C
  3. Paul S. Hirose, 1990 Nov 12
  4. User interface support functions for SEESAT satellite tracking program.
  5.  
  6. 100 - 199
  7.  
  8. Library functions and #defines used in this file:
  9.  
  10. atof, atoi, getchar, isalpha, isspace, NULL, printf, strcmp, strcpy,
  11. strlen, toupper.
  12. */
  13.  
  14. #include "b:seesat.h"    /* global header */
  15.  
  16. extern void printf();
  17. extern int atoi(), getchar(), isalpha(), isspace(),
  18.     strcmp(), strlen(), toupper();
  19. extern char *strcpy();
  20. extern double atof();
  21.  
  22.  
  23. /* Use 0 for normal operation.  Non-zero will make static functions & data
  24. externally visible for testing */
  25. #define NSTAT 0
  26.  
  27. #if NSTAT        /* test mode */
  28. #define STATIC        /* precedes static definitions of functions & data */
  29. #define SC extern    /* precedes declarations of static functions */
  30.  
  31. #else            /* normal mode */
  32. #define STATIC static
  33. #define SC static
  34. #endif
  35.  
  36. /*############################## DATA ##############################*/
  37.  
  38. struct month {
  39.     char *mname;    /* month name */
  40.     int difm;    /* days in full months */
  41. };
  42.  
  43. /* calendar */
  44. STATIC struct month calndr[] = {
  45.     {"JAN",   0}, {"FEB",  31}, {"MAR",  59},
  46.     {"APR",  90}, {"MAY", 120}, {"JUN", 151},
  47.     {"JUL", 181}, {"AUG", 212}, {"SEP", 243},
  48.     {"OCT", 273}, {"NOV", 304}, {"DEC", 334}, {NULL, 365}
  49. };
  50.  
  51. /*################ FUNCTIONS LOCAL TO THIS FILE ################*/
  52.  
  53. SC void cpy0p();    /* strncpy() with leading 0 padding */
  54. SC int leapyr();    /* returns 1 if arg is leap year */
  55. SC char *s_in();    /* input a string with prompt */
  56.  
  57. /*############################## CODE ##############################*/
  58.  
  59. double
  60. atomin(string)
  61. char *string;
  62. /* Returns value (in minutes) of string of form "hhmm:ss.s...".  Leading
  63. minus sign permitted. */
  64. {
  65.     double time;
  66.     char *ptr, c, buf[5];
  67.     int sign;
  68.  
  69.     if (*string == '-') {
  70.         sign = -1;
  71.         ++string;
  72.     } else
  73.         sign = 1;
  74.     ptr = string;
  75.  
  76.     /* point to the colon (or terminating null if no colon) */
  77.     while ((c = *ptr)  &&  c != ':')
  78.         ++ptr;
  79.  
  80.     /* process seconds */
  81.     if (c) {        /* string had a colon */
  82.         time = atof(ptr + 1) / 60.;
  83.         *ptr = '\0';        /* turn ':' to '\0' */
  84.     } else
  85.         time = 0.;
  86.  
  87.     cpy0p(buf, string, 5);        /* buf[] = "hhmm" */
  88.  
  89.     time += atof(buf + 2);        /* add minutes */
  90.     buf[2] = '\0';
  91.     /* add hours, restore sign */
  92.     return (time + atof(buf) * 60.) * sign;
  93. }
  94.  
  95.  
  96. STATIC void
  97. cpy0p(dest, src, n)
  98. char *dest, *src;
  99. int n;
  100. /* Copy n-1 chars from src[] to dest[].  If src[] is too short, pad dest[]
  101. with leading '0's.  If src[] is too long, not all of src[] will be copied. 
  102. dest[] will always receive n-1 chars followed by null terminator. */
  103. {
  104.     int i, len;
  105.  
  106.     len = strlen(src);
  107.     for (i = n; --i; )
  108.         *dest++ = (i > len) ? '0' : *src++;
  109.     *dest = '\0';
  110. }
  111.  
  112.  
  113. char **
  114. degdms(pre, x)
  115. int pre;        /* precision */
  116. double x;
  117. /* Converts x degrees to 3 strings holding degrees, minutes, seconds.  "pre"
  118. specifies rounding and may be 0 - 4:  0 = nearest deg, 1 = nearest 10 min, 2
  119. = 1 min, 3 = 10 sec, 4 = 1 sec.  Domain of x (after rounding):  -1000 < x <
  120. 10000.  Returns pointer to dms[].  If pre was 1 or 2, s[] is garbage.  Both
  121. s[] & m[] are garbage if pre was 0. */
  122. {
  123.     long int lx;
  124.     int sign;
  125.     static int mult[] = {1, 6, 60, 360, 3600};
  126.     static char
  127.         d[5], m[3], sec[3],
  128.         *dms[] = {d, m, sec};
  129.  
  130.     if (x >= 0.)
  131.         sign = 1;
  132.     else {
  133.         sign = -1;
  134.         x = -x;
  135.     }
  136.  
  137.     lx = (long) (x * mult[pre] + .5) * (((unsigned) pre & 1) ? 10 : 1);
  138.     switch (pre) {
  139.     case 4:
  140.     case 3:
  141.         ITOA(sec, (int) (lx % 60));    /* seconds */
  142.         lx /= 60;
  143.     case 2:
  144.     case 1:
  145.         ITOA(m, (int) (lx % 60));    /* minutes */
  146.         lx /= 60;
  147.     }
  148.     ITOA(d, (int) lx * sign);    /* degrees */
  149.     return dms;
  150. }
  151.  
  152.  
  153. double
  154. din(str)
  155. char *str;
  156. /* Input a double, with default value.  Sends '[', str, then "]: " to the
  157. console.  Then waits for user input.  If a only a carriage return is struck,
  158. returns str converted to a double.  If a string is typed, returns the string
  159. converted to double.  Backspacing is allowed. */
  160. {
  161.     char buffer[30];
  162.  
  163.     printf("[%s]:", str);
  164.     if (strlen(s_in(" ", buffer)))
  165.         return atof(buffer);
  166.     else
  167.         return atof(str);
  168. }
  169.  
  170.  
  171. char *
  172. jdstr(jd)
  173. long int jd;    /* Julian Date, unit = days */
  174. /* Converts jd to Gregorian calendar date.  Good for both BC & AD for
  175. practically any date one might want.  More precisely, domain of jd is limited
  176. by largest/smallest year an int can hold, as well as size of buffer[]. 
  177. Returns pointer to year/month/day string, e.g., "1990 JAN 14". */
  178. {
  179.     static char buffer[13];        /* space for -yyyy mmm dd */
  180.     struct month *calp;        /* pointer into calendar */
  181.     int d, m, n;
  182.     int leap;        /* flag; 1 = leap yr */
  183.     char *cp;
  184.  
  185.     /* 1721425 = Julian Date @ 1 BC Dec 31 (Gregorian calendar), 12h UT. 
  186.     365.2425 = days per year (over the 400 yr Gregorian cycle). */
  187.     n = (jd - 1721425) / 365.2425;
  188.     if (n >= 0)
  189.         ++n;
  190.  
  191.     /*  n = estimated year.  Correct the estimate to actual year.  The
  192.     preceding formula can mistakenly yield an AD year from a BC jd, but
  193.     the reverse will never happen.  Therefore, we need only guard against
  194.     n being DECREMENTED to 0 (which is an undefined year). */
  195.  
  196.     while (1) {
  197.         d = jd - julday(n, 0, 0);
  198.         leap = leapyr(n);    /* true if leap year */
  199.         if (d <= 365 + leap  &&  d >= 1)
  200.             break;
  201.         if (d < 1) {
  202.             --n;
  203.             if (n == 0)
  204.                 --n;    /* skip year 0 */
  205.         } else
  206.             ++n;
  207.     }
  208.     ITOA(buffer, n);    /* write the year */
  209.     cp = buffer + strlen(buffer);
  210.     *cp++ = ' ';
  211.  
  212.     /* determine month by moving forward thru the calendar till we
  213.     overshoot, then back up one month */
  214.     calp = calndr;        /* point to Jan */
  215.     m = 0;            /* month counter; 0 = Jan */
  216.     do {
  217.         n = (++calp)->difm;
  218.         if (++m >= 2)    /* March or later */
  219.             n += leap;
  220.     } while (d > n);
  221.     d -= (--calp)->difm + (m >= 2 && leap);
  222.  
  223.     /* write month & day */
  224.     strcpy(cp, calp->mname);
  225.     cp += 3;
  226.     *cp++ = ' ';
  227.     ITOA(cp, d);
  228.     return buffer;
  229. }
  230.  
  231.  
  232. long int
  233. julday(y, m, d)
  234. int y, m, d;        /* year, month (Jan = 0), day */
  235. /* Returns Julian Date (unit = days) corresponding to 12h UT on given date,
  236. Gregorian calendar.  Jan = month 0.  Use -1 for 1 BC, etc.  Any integer
  237. is legal for d. */
  238. {
  239.     int bc;        /* flag; 1 = BC */
  240.  
  241.     if (m > 1)    /* after Feb */
  242.         d += leapyr(y);        /* add 1 if leap yr */
  243.  
  244.     if (y >= 0) {
  245.         --y;
  246.         bc = 0;
  247.     } else {
  248.         y = -(y + 1);
  249.         bc = 1;
  250.     }
  251.     return ((bc ? 366 : 0) + y*365L + y/4 - y/100 + y/400) *
  252.       (bc ? -1 : 1) + calndr[m].difm + d + 1721425;
  253.     /* 1721425 = Julian Date for 1 BC Dec 31 12h, Gregorian calendar */
  254. }
  255.  
  256.  
  257. STATIC int
  258. leapyr(y)
  259. int y;
  260. /* Returns 1 if y is leap year in Gregorian calendar, 0 otherwise.  To
  261. signify BC year use a negative number, e.g., -1 for 1 BC. */
  262. {
  263.     /* For leap year determination purposes, 1 BC = 0, 2 BC = -1, etc. 
  264.     Therefore, we must make an adjustment to y if it's BC. */
  265.     if (y < 0)
  266.         ++y;
  267.     return !(y%4) && y%100  ||  !(y%400);
  268. }
  269.  
  270.  
  271. char *
  272. stoup(string)
  273. char *string;
  274. /* Converts "string" to all upper case, returns "string". */
  275. {
  276.     char *cp;
  277.     int i;
  278.  
  279.     for (cp = string; i = *cp; ++cp)
  280.         if (isalpha(i))
  281.             *cp = toupper(i);
  282.     return string;
  283. }
  284.  
  285.  
  286. STATIC char *
  287. s_in(prompt, buffer)
  288. char *prompt, *buffer;
  289. /* Prints prompt[] on console, puts typed string in buffer[].  Backspacing
  290. will correct typing mistakes.  Will not allow backspacing past the start of
  291. buffer.  Returns pointer to buffer. */
  292. {
  293.     static char c, *ptr, last;
  294.  
  295.     for (ptr = prompt; *ptr; ++ptr)
  296.         ;    /* point to terminating null of prompt */
  297.     last = *(ptr - 1);        /* fetch char before the null */
  298.  
  299.     printf("%s", prompt);
  300.     ptr = buffer;
  301.     while ((c = getchar()) != '\n')
  302.         if (c == '\b')
  303.             if (ptr == buffer)
  304.                 printf("%c", last);
  305.             else
  306.                 --ptr;
  307.         else
  308.             *ptr++ = c;
  309.  
  310.     *ptr = '\0';
  311.     return buffer;
  312. }
  313.  
  314.  
  315. char *
  316. timstr(m)
  317. double m;    /* minutes */
  318. /* Turns m into a string of format "hhmm:ss" (or "-hhmm:ss" if m is
  319. negative), rounded to nearest second.  Be sure that hours will not require
  320. more than two digits.  String will be padded with zeros to fill out all six
  321. digits.  Returns the string. */
  322. {
  323.     static char buf[9];
  324.     char *cp, **cpp;
  325.     int minus;        /* flag; 1 = negative */
  326.  
  327.     cp = buf;
  328.     cpp = degdms(4, m / 60.);
  329.  
  330.     if (m < 0.) {
  331.         *cp++ = '-';
  332.         minus = 1;
  333.     } else
  334.         minus = 0;
  335.     cpy0p(cp, cpp[0] + minus, 3);
  336.     cpy0p(cp + 2, cpp[1], 3);
  337.     cp[4] = ':';
  338.     cpy0p(cp + 5, cpp[2], 3);
  339.  
  340.     return buf;
  341. }
  342.  
  343.  
  344. void
  345. tok()
  346. /* tok() prompts user with '>' and accepts a string.  String is converted to
  347. upper case.  Each ' ' in the string is replaced with '\0' & successive
  348. members of tokens[] point to the sub-strings ("tokens") thus created.  A
  349. character sequence containing spaces is considered a single token if it's
  350. enclosed in quotes (the quotes will not become part of the token).  End of
  351. tokens[] is marked by NULL.  On exit, tokp points to tokens[0]. */
  352. {
  353.     char *cptr;
  354.     char c;
  355.     int notok;            /* flag; 1 = not in a token */
  356.     static char
  357.         *tokens[20],        /* pointers to cmd line tokens */
  358.         buffer[85];        /* command line buffer */
  359.  
  360.     /* display '>', accept command line */
  361.     s_in(">", buffer);
  362.     stoup(buffer);
  363.     cptr = buffer - 1;
  364.     tokp = tokens;        /* point to 1st element of tokens[] */
  365.     notok = 1;        /* set "not in token" flag true */
  366.     while (c = *++cptr)    /* tokenize the command line */
  367.         if (isspace(c)) {
  368.             notok = 1;
  369.             *cptr = '\0';    /*  replace ' ' with '\0' */
  370.         } else if (notok) {    /* first char of a token */
  371.             if (c != '"')
  372.                 *tokp++ = cptr;
  373.             else {        /* quoted token */
  374.                 *tokp++ = ++cptr;
  375.                 while (*++cptr != '"')
  376.                     ;    /* find closing '"' */
  377.                 *cptr = '\0';
  378.             } notok = 0;
  379.         }
  380.     *tokp = NULL;        /* terminate tokens[] */
  381.     tokp = tokens;
  382. }
  383.  
  384.  
  385. void
  386. tokjum(t)
  387. struct jdtim *t;
  388. /* Converts command line arguments (pointed to by global "tokp") into Julian
  389. Date & minutes.  NO conversion to UTC occurs!  tokp[1] thru [4] = {year,
  390. month, day, time}.  Month must be first 3 letters of name.  Year, month, or
  391. day may be omitted if the arguments to its left are also omitted.  On exit,
  392. tokp will point to next item following the arguments.  Returns JD & minutes
  393. in struct "t". */
  394. {
  395.     static int date[3];    /* default year, month (Jan = 0), day */
  396.  
  397.     struct month *calp;    /* pointer into calendar */
  398.     int m, n;
  399.     char *cp, **cpp;
  400.  
  401.     /* Set n to # of date arguments.  Can be 0 - 3. */
  402.  
  403.     /* point cpp to next arg beginning with a letter, or end of cmd line,
  404.     whichever comes first */
  405.     for (cpp = tokp + 1; (cp = *cpp) && !isalpha(*cp); ++cpp)
  406.         ;
  407.  
  408.     if (cp == NULL)        /* reached end of command line */
  409.         n = cpp - tokp - 2;
  410.     else {            /* is cp[] a month name? */
  411.         for (calp = calndr + 11, m = 11; m >= 0 &&
  412.           strcmp(cp, calp->mname); --calp, --m)
  413.             ;    /* look for cp[] in calendar */
  414.         /* if m >= 0 it's a month name, otherwise it's next cmd */
  415.         n = cpp - tokp + ((m >= 0) ? 1 : -2);
  416.     } if (n > 3  ||  n < 0) {
  417.         printf("%s:  INCORRECT ARGUMENTS\n", *tokp);
  418.         LONGJMP(reset, 1);
  419.     }
  420.     /* if year, month, or day were given, set them as new defaults */
  421.     switch (n) {
  422.     case 3:
  423.         date[0] = atoi(*++tokp);    /* year */
  424.     case 2:
  425.         date[1] = m;            /* month */
  426.         ++tokp;
  427.     case 1:
  428.         date[2] = atoi(*++tokp);    /* day */
  429.     }
  430.     if (date[0] == 0) {    /* year = 0, i.e., full date not given yet */
  431.         printf("DATE HAS NOT BEEN SET\n");
  432.         LONGJMP(reset, 1);
  433.     }
  434.     /* compute Julian Date & time of day */
  435.     t->jd = julday(date[0], date[1], date[2]);
  436.     t->time = atomin(*++tokp);
  437.  
  438.     ++tokp;        /* point to next cmd line token */
  439. }
  440.  
  441.  
  442. double
  443. tokmin()
  444. /* Same as tokjum() except returns epoch expressed as minutes instead of
  445. Julian Date & minutes, and the time zone is Greenwich. */
  446. {
  447.     struct jdtim t;
  448.  
  449.     tokjum(&t);
  450.     return t.jd * xmnpda - 720. + t.time + zd;
  451. }
  452. --m)
  453.             ;    /* look for cp[] in calendar */
  454.         /* if m >= 0 it's a month name, otherwise it's next cmd */
  455.         n